vue

[Vuetorials] 4. 내장 컴포넌트

6 min read|18. 11. 5.

Vue 에서 제공하고 있는 컴포넌트에 대해 알아보는 포스팅.

Slot

일단 이 Slot 이라는 것은 Vue 에서 특별히 만든 그런 기능이 아님. w3c/proposals - Slots-Proposal.md가 있음. 이 Slots 을 제대로 이해하려고 했더니 Shadow Tree까지 봐야함. 자세한 내용은 관련 Spec 문서를 봐야 함. API는 별 게 없음. 공식 문서 설명도 딱히 도움이 되진 않음. 일단 문법 자체가 처음 보면 익숙하지 않아서 부모-자식 이 부분이 약간 헷갈림.

언제 쓰는가

Vue 에서 component 를 등록하고 렌더링할 때 보통 props로 데이터를 전달하거나 함수를 전달함. 그런데 children 에 HTML 또는 Vue 컴포넌트를 전달해서 렌더링하고 싶을 때가 있음. 이 때 slot 을 사용할 수 있음.

사실 React 사용자에겐 '응? 그냥 props 로 JSX 넘겨주면 되지 않나?' 할 수 있음. Vue 에서는 components에 컴포넌트를 등록해야 template에서 렌더링 할 수 있음. 근데 props로 전달함과 동시에 components에 등록할 수 없음.

그냥 props 로 전달하는 것보다 slot 이 더 Composability(합성 가능성)를 극대화 할 수 있는 기능이라고 하는데, 아직 감이 잘 안 잡힘.

<template>
  <div id="container">
    <header><slot name="todo-header" /></header>
    <section><slot name="todo-container" /></section>
    <section><slot name="todo-filters" /></section>
    <footer><slot name="todo-footer" :author="&quot;Jbee&quot;" /></footer>
  </div>
</template>

slot 을 사용하는 가장 쉽고 대표적인 예제는 layout 을 잡기 위한 .vue 임. 위와 같이 TodoLayout.vue를 지정한 후,

<template>
  <todo-layout>
    <!-- 정의한 컴포넌트를 slot으로 배포 -->
    <todo-title msg="TODO APP" slot="todo-header"> </todo-title>

    <!-- 축약형 -->
    <todo-container slot="todo-container" />

    <!-- scope를 통해 전달받은 props를 렌더링 -->
    <div slot="todo-footer" slot-scope="props">
      Copyright: @{{ props.author }}
    </div>
  </todo-layout>
</template>

이렇게 todo-layout 컴포넌트에 주입할 수 있음. slot="A" 어트리뷰트와 <slot name="A" />로 부모-자식 관계를 정의함.

component

동적 컴포넌트를 정의할 때 편리한 내장 컴포넌트 API. is라는 속성과 함께 사용됨.

<template>
  <component v-bind:is="currentFilterView"></component>
  <!-- shorten -->
  <!-- <component :is="currentFilterView"></component> -->
</template>
<script>
  export default {
    component: {
      A,
      B,
      C,
    },
  }
</script>

currentFilterView는 Vue 컴포넌트에서 data로 지정된 속성임. 이 값에 A 또는 B 또는 C 값(컴포넌트이름)이 들어갈 경우, component 태그에 A 또는 B 또는 C컴포넌트가 렌더링 됨. component 태그 하위에 렌더링 되는게 아니라 바로 그 자리에 대체됨. 언뜻보면 단순한 switch statement sugar syntax 같지만, keep-alive 라는 내장 컴포넌트로 감싸줄 경우, cache 를 타게 됨.

keep-alive

무엇이 어떻게 caching 되는가를 보면 인스턴스를 destroy 하지 않고 남겨둠. 즉 keep-alive라는 추상 엘리먼트로 감싸져있는 컴포넌트들이 변경될 때, 사라질 인스턴스를 메모리에서 제거하지 않음. 이로 인해 불필요한 re-render 를 막고 활성화되을 때 변경되었던 상태가 비활성화 후 다시 활성화 되었을 때 유지 됨. 공식 문서에서는 transition 내장 컴포넌트와 함께 사용하여 애니메이션 된 상태를 유지할 때 사용하기도 한다고 되어있음.

<keep-alive> <component :is="currentFilterView"></component> </keep-alive>

아까 component를 정의한 부모에 keep-alive 태그로 감싸주면 됨. keep-alive 하위에 렌더링되는 컴포넌트들은 두 가지 hook 이 mixin 으로 추가됨. activated, deactivated 두 가지 훅(hook)은 해당 컴포넌트가 활성화 될 때, 비활성화 될 때 호출됨.

:include, :exclude디렉티브를 통해서 caching 을 적용할 컴포넌트와 적용하지 않을 컴포넌트를 적용할 수 있음. String, 정규식, 배열을 전달할 수 있음. (관련 코드)

마무리

transitiontrasition-group은 animation 관련하여 함께 다루는 것이 좋을 듯하여 이번 장에서 다루지 않음. React 는 개발자 너희들이 알아서 해라 식이었다면 Vue 는 computed도 그렇고 keep-alive도 그렇고 라이브러리 자체에서 제공하고 있는 API 를 충분히 활용할 수 있을 듯 함.

Reference

  • https://skyronic.com/blog/vue-slots-example
  • https://daveceddia.com/pluggable-slots-in-react-components/